
package com.ypan.uninstaller.utils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.widget.ImageView;

import com.ypan.uninstaller.R;
import com.ypan.uninstaller.MainApp;
import com.ypan.uninstaller.adapter.ApkInfo;
import com.ypan.uninstaller.logger.SLog;

/**
 * @ClassName: IconCache
 * @Description: IconCache
 * @author Administrator
 * @date 2012-9-3 下午11:30:56
 */
public class IconCache {
    private static final String TAG = IconCache.class.getSimpleName();
    // icon的内存Cache
    private static volatile LruCache<String, Bitmap> mImageCache;
    // 用于存放icon imageview控件的Map
    private static volatile Map<ImageView, String> mImageViews;
    // 网络下载和解码线程池
    private volatile ExecutorService mPool = null;

    // 统计Cache命中率
    private long mGetCount = 0; // 获取次数
    private long mHitCount = 0; // Cache命中次数

    private static Object classLock = IconCache.class;
    private static IconCache sInstance = null;
    private Bitmap mDefaultIcon = null; // 默认icon

    public static IconCache getInstance() {
        synchronized (classLock) {
            if (sInstance == null) {
                sInstance = new IconCache();
            }
            return sInstance;
        }
    }

    public synchronized void getIcon(final String md5,
            final ImageView imageView, final ApkInfo info) {
        Bitmap cacheBitmap = null;
        mImageViews.put(imageView, md5);
        //SLog.d(TAG, "add imageView = " + imageView + ", md5 = " + md5);
        cacheBitmap = loadHeader(md5,
                    new ImageCallback() {
                        @Override
                        public void onLoadImage(Bitmap bm, String md5, ApkInfo info) {
                            String oldMd5 = mImageViews.get(imageView);
                            if (!TextUtils.isEmpty(oldMd5) && oldMd5.equals(md5)) {
                                setImage(imageView, bm);
//                                SLog.d(TAG, "bm.getWidth() = " + bm.getWidth()
//                                        + " ,bm.getHeight() = " + bm.getHeight());
                            }
                           // SLog.d(TAG, "oldMd5 = " + oldMd5 + ", md5 = " + md5);

                        }
                    }, info);
        setImage(imageView, cacheBitmap);
    }

    /**
     * 设置icon
     * 
     * @param imageView
     * @param bm
     * @param item
     */
    private void setImage(final ImageView imageView, final Bitmap bm) {
        if (bm == null) {
            imageView.setImageBitmap(mDefaultIcon);
        } else {
            imageView.setImageBitmap(bm);
        }
    }

    private IconCache() {
        mImageCache = new LruCache<String, Bitmap>(100);
        mImageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
        PriorityThreadFactory threadFactory = new PriorityThreadFactory("uninstall-icon",
                android.os.Process.THREAD_PRIORITY_BACKGROUND);
        mPool = Executors.newFixedThreadPool(1, threadFactory); // 固定大小的线程池
        BitmapDrawable drawable = (BitmapDrawable) MainApp.sInstance.getResources()
                .getDrawable(R.drawable.def_icon);
        mDefaultIcon = drawable.getBitmap();
    }

    private Bitmap loadHeader(final String md5, final ImageCallback imageCallback,
            final ApkInfo info) {
        mGetCount++;
        Bitmap bm = mImageCache.get(md5);
        if (bm != null) {
            mHitCount++;
//            SLog.d(TAG, "mHitCount = " +
//                        mHitCount
//                        + " , mGetCount = " + mGetCount);
            return bm;
        }
        if (imageCallback != null) {
            final Handler handler = new Handler() {
                @Override
                public void handleMessage(Message message) {
                    imageCallback.onLoadImage((Bitmap) message.obj, md5, info);
                }
            };
            mPool.execute(new Runnable() {

                @Override
                public void run() {
                    if (!mImageViews.containsValue(md5)) {
                       // SLog.d(TAG, "md5 滑动过去了  不需要解码 = " + md5);
                        return;
                    }
                    //SLog.d(TAG, "解码开始  md5 = " + md5);
                    long stime = System.currentTimeMillis();
                    Bitmap bm = getBitmap(info, md5);
                    mImageCache.put(md5, bm);
                    Message message = handler.obtainMessage(0, bm);
                    handler.sendMessage(message);
                    long etime = System.currentTimeMillis();
                   // SLog.d(TAG, "解码结束  md5 = " + md5 + " ,time = " + (etime - stime) + " ms");
                }
            });
        }
        return null;
    }

    private Bitmap getBitmap(ApkInfo info, String md5) {
        Bitmap bm = FileUtils.JpegToBitmap(Define.ICON_CACHE_PATH + md5);
        if (bm != null) {
            return bm;
        }
        if (info.backpath != null) {
           // SLog.d(TAG, "从apk文件解码icon");
            return getBitmapByPkgPath(info.backpath, md5);
        } else {
           // SLog.d(TAG, "从pkManager解码icon");
            return getBitmapByPkgname(info.packageName, md5);
        }
    }

    private Bitmap getBitmapByPkgname(String pkgName, String md5) {
        PackageManager pkManager = MainApp.sInstance.getPackageManager();
        List<PackageInfo> all = pkManager.getInstalledPackages(0);
        PackageInfo pkInfo = getPackageInfo(pkgName, all);
        if (pkInfo != null) {
            Bitmap bm = ((BitmapDrawable) pkManager
                    .getApplicationIcon(pkInfo.applicationInfo)).getBitmap();
            if (bm != null) {
                FileUtils.Bitmap2JPEG(bm, Define.ICON_CACHE_PATH + md5);
            }
            return bm;
        } else {
            return null;
        }
    }

    private PackageInfo getPackageInfo(String pkgName, List<PackageInfo> all) {
        if (pkgName == null || all == null) {
            return null;
        }
        PackageInfo pkinfo = null;
        for (PackageInfo info : all) {
            if (pkgName.equals(info.packageName)) {
                pkinfo = info;
                break;
            }
        }
        if (pkinfo == null) {
            SLog.w(TAG, "can not find package = " + pkgName);
        }
        return pkinfo;
    }

    private Bitmap getBitmapByPkgPath(String path, String md5) {
        return PackageUtils.getUninstallAPKIcon(path, md5);
    }
}
